// thread.h
//	Data structures for managing threads.  A thread represents
//	sequential execution of code within a program.
//	So the state of a thread includes the program counter,
//	the processor registers, and the execution stack.
//
// 	Note that because we allocate a fixed size stack for each
//	thread, it is possible to overflow the stack -- for instance,
//	by recursing to too deep a level.  The most common reason
//	for this occuring is allocating large data structures
//	on the stack.  For instance, this will cause problems:
//
//		void foo() { int buf[1000]; ...}
//
//	Instead, you should allocate all data structures dynamically:
//
//		void foo() { int *buf = new int[1000]; ...}
//
//
// 	Bad things happen if you overflow the stack, and in the worst
//	case, the problem may not be caught explicitly.  Instead,
//	the only symptom may be bizarre segmentation faults.  (Of course,
//	other problems can cause seg faults, so that isn't a sure sign
//	that your thread stacks are too small.)
//
//	One thing to try if you find yourself with seg faults is to
//	increase the size of thread stack -- ThreadStackSize.
//
//  	In this interface, forking a thread takes two steps.
//	We must first allocate a data structure for it: "t = new Thread".
//	Only then can we do the fork: "t->fork(f, arg)".
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.

#ifndef THREAD_H
#define THREAD_H

#include "copyright.h"
#include "utility.h"
#include "syscall.h"

#ifdef USER_PROGRAM
#include "machine.h"
#include "addrspace.h"
#include "list.h"
class ChildThread;
class Mutex;
#endif

// CPU register state to be saved on context switch.
// The SPARC and MIPS only need 10 registers, but the Snake needs 18.
// For simplicity, this is just the max over all architectures.
#define MachineStateSize 18


// Size of the thread's private execution stack.
// WATCH OUT IF THIS ISN'T BIG ENOUGH!!!!!
#define StackSize	(4 * 1024)	// in words

// Thread state
enum ThreadStatus { JUST_CREATED, RUNNING, READY, BLOCKED };

// external function, dummy routine whose sole job is to call Thread::Print
extern void ThreadPrint(int arg);

class OpenFile;

struct OpenFileHandle {
    OpenFileHandle() {}
    OpenFileHandle(OpenFile* aFile, char* aName, int aID):
        file(aFile),
        name(aName),
        id(aID) {}

	~OpenFileHandle() {}
    OpenFile * file;
    char* name;
    int id;
};

// The following class defines a "thread control block" -- which
// represents a single thread of execution.
//
//  Every thread has:
//     an execution stack for activation records ("stackTop" and "stack")
//     space to save CPU registers while not running ("machineState")
//     a "status" (running/ready/blocked)
//
//  Some threads also belong to a user address space; threads
//  that only run in the kernel have a NULL address space.

class Thread {
private:
    // NOTE: DO NOT CHANGE the order of these first two members.
    // THEY MUST be in this position for SWITCH to work.
    int* stackTop;			 // the current stack pointer
    int machineState[MachineStateSize];  // all registers except for stackTop

public:
    Thread(char* debugName);		// initialize a Thread
    Thread(char* debugName, int priority);

#ifdef USER_PROGRAM
    Thread(char* debugName, Thread* parent);
#endif

    ~Thread(); 				// deallocate a Thread
    // NOTE -- thread being deleted
    // must not be running when delete
    // is called
    void init();                        //Set attributes to defaults.

    // basic thread operations

    void Fork(VoidFunctionPtr func, int arg); 	// Make thread run (*func)(arg)
    void Yield();  				// Relinquish the CPU if any
    // other thread is runnable
    void Sleep();  				// Put the thread to sleep and
    // relinquish the processor
    void Finish();  				// The thread is done executing

    void CheckOverflow();   			// Check if thread has
    // overflowed its stack
    int getPriority();


    void setStatus(ThreadStatus rtn_status) {
        status = rtn_status;
    }
    char* getName() {
        return (name);
    }
    void Print() {
        printf("%s, ", name);
    }

    OpenFile* getFileHandle(int id);
    int addFileHandle(char* filename, OpenFile* file);
    void closeFileHandle(int id);

private:
    // some of the private data for this class is listed above

    int* stack; 	 		// Bottom of the stack
    // NULL if this is the main thread
    // (If NULL, don't deallocate stack)
    ThreadStatus status;		// ready, running or blocked
    char* name;
    int priority;

    void StackAllocate(VoidFunctionPtr func, int arg);
    // Allocate a stack for thread.
    // Used internally by Fork()

    // A thread running a user program actually has *two* sets of CPU registers
    // one for its state while executing user code, one for its state
    // while executing kernel code.
#ifdef USER_PROGRAM

    int userRegisters[NumTotalRegs];	// user-level CPU register state

    int return_status;
    int next_id;
    ChildThread* parent_record;

    List* openFileList;
    int nextFileID;

public:
    void notifyParent(int rtn_status);
    int getID();
    void SaveUserState();		// save user-level register state
    void RestoreUserState();		// restore user-level register state
    int Join(int id);

    AddrSpace *space;			// User code this thread is running.
    Mutex* child_lock;
    ChildThread* child;
#endif //USERPROG
};

// Magical machine-dependent routines, defined in switch.s

extern "C" {
    // First frame on thread execution stack;
    //   	enable interrupts
    //	call "func"
    //	(when func returns, if ever) call ThreadFinish()
    void ThreadRoot();

    // Stop running oldThread and start running newThread
    void SWITCH(Thread *oldThread, Thread *newThread);
}

#endif
// THREAD_H
